#coding: utf-8
from datetime import datetime
from app.models.model import *
from flask_login import UserMixin
from flask import current_app, request
from werkzeug.security import generate_password_hash, check_password_hash
from app.includes import file


from itsdangerous import URLSafeSerializer


PREFIX = ""


class User(UserMixin, db.Model):
    """ user table """
    __tablename__ = db.PREFIX + PREFIX + "user"
    __table_args__ = {
        "mysql_engine": "InnoDB",
        "mysql_charset": "utf8"
    }

    id = db.Column(db.Integer, primary_key=True, nullable=False)
    username = db.Column(db.String(255), unique=True, nullable=False, index=True, default="")
    nickname = db.Column(db.String(255), nullable=False, default="")
    password = db.Column(db.String(255), default="")
    avatar = db.Column(db.String(255),  default="")
    updatetime = db.Column(db.DateTime, default=datetime.now, nullable=False)
    timestamp = db.Column(db.DateTime, default=datetime.now, nullable=False)
    books = db.relationship("Book", backref="user", lazy="dynamic")
    access = db.Column(db.Integer, default=0, nullable=False, index=True)

    @staticmethod
    def add(username, password):
        user = User.query.filter_by(username=username).first()
        if user is not None:
            return

        user = User()

        manager = User.query.filter_by(access=1).first()
        if manager is None:
            user.access = 1

        user.username = username
        user.nickname = username
        user.password = generate_password_hash(password)
        user.avatar = file.new_avatar()
        db.session.add(user)
        db.session.commit()
        return user

    @staticmethod
    def get(id):
        return User.query.filter_by(id=id).first()

    @staticmethod
    def getbyname(username):
        return User.query.filter_by(username=username).first()

    @staticmethod
    def page(page, per_page):
        return User.query.paginate(page, per_page=per_page, error_out=False)

    def setting(self, nickname):
        self.nickname = nickname

    def change_password(self, password):
        print 'password', password
        self.password = generate_password_hash(password)

    def verify_password(self, password):
        return check_password_hash(self.password, password)

    def page_manager(self, page, per_page):
        from .book import Book
        books = Book.query.filter(Book.user_id!=self.id) \
            .options(db.Load(Book).undefer("brief"))\
            .order_by(Book.publish_timestamp.desc())\
            .paginate(page, per_page=per_page, error_out=False)
        return books

    def page_other(self, page, per_page):
        from .book import Book
        books = Book.query.filter(Book.user_id!=self.id) \
            .filter_by(access=2) \
            .options(db.Load(Book).undefer("brief"))\
            .order_by(Book.publish_timestamp.desc())\
            .paginate(page, per_page=per_page, error_out=False)
        return books

    def page_my(self, page, per_page):
        from .book import Book
        books = Book.query.filter_by(user_id=self.id)\
            .options(db.Load(Book).undefer("brief"))\
            .order_by(Book.publish_timestamp.desc())\
            .paginate(page, per_page=per_page, error_out=False)
        return books

    def page_draft(self, page, per_page):
        from .book import Book
        books = Book.query.filter_by(user_id=self.id)\
                .filter(Book.updatetime>Book.publish_timestamp)\
                .options(db.Load(Book).undefer("brief"))\
                .order_by(Book.publish_timestamp.desc())\
                .paginate(page, per_page=per_page, error_out=False)
        return books

    def count_book(self):
        return self.books.count()

    def count_draft(self):
        from .book import Book
        num = Book.query.filter_by(user_id=self.id)\
                .filter(Book.updatetime>Book.publish_timestamp)\
                .count()
        return num

    def _20px_avatar(self):
        image_path = current_app.config["AVATAR_PATH"]
        return "/".join([image_path, "20_20_{}".format(self.avatar)])
    
    def _50px_avatar(self):
        image_path = current_app.config["AVATAR_PATH"]
        return "/".join([image_path, "50_50_{}".format(self.avatar)])

    def origin_avatar(self):
        image_path = current_app.config["AVATAR_PATH"]
        return "/".join([image_path, self.avatar])

    def is_manager(self):
        return True if self.access else False

    def get_users_can_manager(self, page, per_page):
        if self.access > 0:
            return User.query.paginate(page, per_page=per_page, error_out=False)
        else:
            return User.query.filter_by(id=self.id).paginate(page, per_page=per_page, error_out=False)

    def get_id(self, life_time=6 * 60 * 60):
        key = current_app.config.get('SECRET_KEY', 'The secret key')
        s = URLSafeSerializer(key)
        token = s.dumps((self.id, self.username, self.password, life_time))
        return token


@login_manager.user_loader
def load_user(token):
    # print u'user loader id is : {id}'.format(id=id)

    key = current_app.config.get('SECRET_KEY', 'The secret key')
    try:
        s = URLSafeSerializer(key)
        id, username, password, life_time = s.loads(token)
    except Exception, e:
        print 'token had benn modified!'
        return  None

    user = User.get(id)
    if user:
        if str(password) != str(user.password):
            print 'the password in token is not matched!'
            return None
        if str(username) != str(user.username):
            print 'the username in token is not matched!'
            return None
    else:
        print 'the user is not found, the token is invalid!'
        return None

    return user


class Visitor(db.Model):
    """ user table """
    __tablename__ = db.PREFIX + PREFIX + "visitor"
    __table_args__ = {
        "mysql_engine": "InnoDB",
        "mysql_charset": "utf8"
    }

    id = db.Column(db.Integer, primary_key=True, nullable=False)
    ip = db.Column(db.String(255), unique=True, nullable=False, index=True, default="")
    login_is_lock = db.Column(db.Integer, default=0, nullable=False)
    login_lock_time = db.Column(db.DateTime, default=datetime.now, nullable=False)
    error_num = db.Column(db.Integer, default=0, nullable=False)

    @staticmethod
    def get(ip):
        return Visitor.query.filter_by(ip=ip).first()

    @staticmethod
    def add(ip):
        visitor = Visitor.query.filter_by(ip=ip).first()
        if visitor is not None:
            return visitor

        visitor = Visitor()
        visitor.ip = ip
        db.session.add(visitor)
        db.session.commit()
        return visitor

    def unlock(self):
        self.login_is_lock = 0
        self.error_num = 0
        self.login_lock_time = datetime.now()
        db.session.commit()

    def add_error_num(self):
        self.error_num += 1
        if self.error_num >= 100:
            self.login_is_lock = 1
            self.login_lock_time = datetime.now()
        db.session.commit()